package com.fly.base.util;

import java.awt.*;
import java.awt.image.BufferedImage;

/**
 * 感知哈希算法
 *
 * @author dongpengfei
 */
public class PerceptualHashAlgorithm {
    /**
     * 图像缩放后宽度
     */
    private final static int WIDTH = 8;

    /**
     * 图像缩放后长度
     */
    private final static int HEIGHT = 8;

    /**
     * 标准汉明距离，小于该值则认为是同一张图片
     */
    private final static int STANDARD_HAMMING_DISTANCE = 5;

    /**
     * 平均哈希算法
     *
     * @param src 原始图片
     * @return 图片指纹
     */
    public static String aHash(BufferedImage src) {
        // 1. 缩放图片
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_BGR);
        Graphics graphics = image.createGraphics();
        graphics.drawImage(src, 0, 0, WIDTH, HEIGHT, null);
        // 2.简化色彩，计算平均灰度值
        int grayTotal = 0;
        for (int i = 0; i < HEIGHT; i++) {
            for (int j = 0; j < WIDTH; j++) {
                int pixel = image.getRGB(j, i);
                int gray = gray(pixel);
                grayTotal += gray;
            }
        }
        int grayAvg = (grayTotal / (WIDTH * HEIGHT));
        // 3.计算各个像素点与平均灰度值的差异
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < HEIGHT; i++) {
            for (int j = 0; j < WIDTH; j++) {
                int pixel = image.getRGB(j, i);
                int gray = gray(pixel);
                if (gray >= grayAvg) {
                    sb.append("1");
                } else {
                    sb.append("0");
                }
            }
        }
        return sb.toString();
    }

    /**
     * 计算灰度值
     *
     * @param rgb
     * @return
     */
    private static int gray(int rgb) {
        // 将最高位（24-31）的信息（alpha通道）存储到a变量
        int a = rgb & 0xff000000;
        // 取出次高位（16-23）红色分量的信息
        int r = (rgb >> 16) & 0xff;
        // 取出中位（8-15）绿色分量的信息
        int g = (rgb >> 8) & 0xff;
        // 取出低位（0-7）蓝色分量的信息
        int b = rgb & 0xff;
        // NTSC luma，算出灰度值
        rgb = (r * 77 + g * 151 + b * 28) >> 8;
        // 将灰度值送入各个颜色分量
        return a | (rgb << 16) | (rgb << 8) | rgb;
    }

    public static int difference(String finger1, String finger2) {
        char[] ch1 = finger1.toCharArray();
        char[] ch2 = finger2.toCharArray();
        int diffCount = 0;
        int total = WIDTH * HEIGHT;
        for (int i = 0; i < total; i++) {
            if (ch1[i] != ch2[i]) {
                diffCount++;
            }
        }
        return diffCount;
    }
}
